#ifndef UTIL_H_
#define UTIL_H_

#include <stdio.h>
#include <stdlib.h>

#include <iostream>
#include <time.h>
#include  <string>
#include "rectype.h"
#include "chararray.h"
#include <sstream>
#include <bitset>
#include <math.h>


using namespace std;

namespace opsrc
{
    namespace stdf
    {
        struct Util
        {

            inline static endian testByteOrder() {

                short int word = 0x0001;
                char *byte = (char *) &word;
                return(byte[0] ? little_endian : big_endian);
            };

            inline static endian stdfCpuTypeEndian(int stdfFarRecCpuByteValue) {

                return stdfFarRecCpuByteValue == 1? big_endian: little_endian;
            }


            inline static unsigned short int swapbit16(unsigned short int x)
            {
                unsigned short int t = ((x & 0xff00) >> 8) | ((x & 0x00ff) << 8 );
                return t;
            }

            inline static unsigned short int convertCharToShortInt(unsigned char* x) {

                char v[2];
                v[0] = *x;
                v[1] = *(x+1);
                int sum=0;


                if (v[1] & 0x01)  sum +=1;
                if (v[1] & 0x02)  sum +=2;
                if (v[1] & 0x04)  sum +=4;
                if (v[1] & 0x08)  sum +=8;
                if (v[1] & 0x10)  sum +=16;
                if (v[1] & 0x20)  sum +=32;
                if (v[1] & 0x40)  sum +=64;
                if (v[1] & 0x80)  sum +=128;
                if (v[0] & 0x01)  sum +=256;
                if (v[0] & 0x02)  sum +=512;
                if (v[0] & 0x04)  sum +=1024;
                if (v[0] & 0x08)  sum +=2048;
                if (v[0] & 0x10)  sum +=4096;
                if (v[0] & 0x20)  sum +=8192;
                if (v[0] & 0x40)  sum +=16384;
                if (v[0] & 0x80)  sum +=32768;

                return sum;
/*
                unsigned short int a =  static_cast<unsigned short int>(*x);
                a = (a << 8 ) & 0xFF00;  // shift 1 byte left
                unsigned short int b =  static_cast<unsigned short int>(*(x+1));

                b = 0x00FF & b;
                unsigned short int val = a | b ;
                return val;
*/
            }

            //added by Jimmy @ 2010-04-08 to handle signed char
            inline static signed short int convertCharToShort(char* x, int) {

                signed short int a =  static_cast<signed short int>(*x);
                return a;

            }


            inline static unsigned int swapbit32(unsigned int x )
            {
                unsigned int t = ((x & 0xff000000) >> 24) | \
	     			 ((x & 0x00ff0000) >>  8) | \
	    			 ((x & 0x0000ff00) <<  8) | \
	     			 ((x & 0x000000ff) << 24);
                return t;
            }

            inline static unsigned long swapbit64(long x )
            {
                unsigned long t  = ((x & 0xff00000000000000) >> 56) | \
                                   ((x & 0x00ff000000000000) >> 40) | \
                                   ((x & 0x0000ff0000000000) >> 24) | \
                                   ((x & 0x000000ff00000000) >>  8) | \
                                   ((x & 0x00000000ff000000) <<  8) | \
                                   ((x & 0x0000000000ff0000) << 24) | \
                                   ((x & 0x000000000000ff00) << 40) | \
                                   ((x & 0x00000000000000ff) << 56);
                return t;
            }



            // return YYYY-MM-DD hh:mm:ss string format from long datetime value
            inline static string convertDtToMysqlDtFormat(long x) {

                tm* pt = convertUnixTime2TM(x);
                tm&  t = *pt;

                std::stringstream ss;
                ss << (1900 + t.tm_year) << "-" ;

                if (t.tm_mon >9)
                    ss << t.tm_mon << "-" ;
                else
                    ss << "0" << t.tm_mon << "-" ;

                if (t.tm_mday > 9)
                    ss << t.tm_mday << " " ;
                else
                    ss << "0" << t.tm_mday << " " ;

                if (t.tm_hour > 9)
                    ss << t.tm_hour << ":" ;
                else
                    ss << "0" << t.tm_hour << ":" ;

                if (t.tm_sec > 9)
                    ss << t.tm_sec ;
                else
                    ss << "0" << t.tm_sec ;

                return ss.str();


            }

            inline static string getCpuEndian(unsigned int cpu)  {
                    string res =  (cpu == 0 || cpu == 2 )? "small endian" : "big endian" ;
                    return res;
            }

            inline static struct tm* convertUnixTime2TM(char *x) {
                time_t tmv = ((*x << 24) & 0xFF000000 ) | ((*(x+1) << 16) & 0x00FF0000 ) | ((*(x+2) << 8) & 0x0000FF00 ) | (*(x+3));

                ///updated by Jimmy @ 2010-04-09, time information already in local time, do not need to further adjust, use gmtime instead
                struct tm* tminfo = gmtime(&tmv);
                return tminfo;
            }

            inline static struct tm* convertUnixTime2TM(long x) {

                time_t tmv = (time_t) x;

                //updated by Jimmy @ 2010-04-09, time information already in local time, do not need to further adjust, use gmtime instead
                struct tm* tminfo = gmtime(&tmv);
                return tminfo;
            }

            inline static string asciiTime(long x) {
                string val = asctime(	convertUnixTime2TM(x) );
                // remain carriage return
                val = val.erase(val.size()-1, 1);
                return val;
            }

            inline static unsigned int charToUnsignedInt(char *x) {
                unsigned int val = 0x0000FFFF & ( (*x << 8) | *(x+1) ) ;
                return val;
            }

            inline static void swapByteChar(char* x, int L) {
                if (L==2) {
                    char tmp[2];
                    tmp[0] = *x;
                    tmp[1] = *(x+1);
                    *x = tmp[1];
                    *(x+1) = tmp[0];
                    return;
                }

                if (L==4) {
                    char tmp[4];
                    tmp[0] = *x;
                    tmp[1] = *(x+1);
                    tmp[2] = *(x+2);
                    tmp[3] = *(x+3);
                    *x = tmp[3];
                    *(x+1) = tmp[2];
                    *(x+2) = tmp[1];
                    *(x+3) = tmp[0];
                    return;
                }

                if (L==8) {
                    char tmp[8];
                    tmp[0] = *x;
                    tmp[1] = *(x+1);
                    tmp[2] = *(x+2);
                    tmp[3] = *(x+3);
                    tmp[4] = *(x+4);
                    tmp[5] = *(x+5);
                    tmp[6] = *(x+6);
                    tmp[7] = *(x+7);
                    *x = tmp[7];
                    *(x+1) = tmp[6];
                    *(x+2) = tmp[5];
                    *(x+3) = tmp[4];
                    *(x+4) = tmp[3];
                    *(x+5) = tmp[2];
                    *(x+6) = tmp[1];
                    *(x+7) = tmp[0];
                    return;
                }

            }

            inline static void swapByteChar(unsigned char* x, int L) {
                if (L==2) {
                    unsigned char tmp[2];
                    tmp[0] = *x;
                    tmp[1] = *(x+1);
                    *x = tmp[1];
                    *(x+1) = tmp[0];
                    return;
                }

                if (L==4) {
                    unsigned char tmp[4];
                    tmp[0] = *x;
                    tmp[1] = *(x+1);
                    tmp[2] = *(x+2);
                    tmp[3] = *(x+3);
                    *x = tmp[3];
                    *(x+1) = tmp[2];
                    *(x+2) = tmp[1];
                    *(x+3) = tmp[0];
                    return;
                }

                if (L==8) {
                    unsigned  char tmp[8];
                    tmp[0] = *x;
                    tmp[1] = *(x+1);
                    tmp[2] = *(x+2);
                    tmp[3] = *(x+3);
                    tmp[4] = *(x+4);
                    tmp[5] = *(x+5);
                    tmp[6] = *(x+6);
                    tmp[7] = *(x+7);
                    *x = tmp[7];
                    *(x+1) = tmp[6];
                    *(x+2) = tmp[5];
                    *(x+3) = tmp[4];
                    *(x+4) = tmp[3];
                    *(x+5) = tmp[2];
                    *(x+6) = tmp[1];
                    *(x+7) = tmp[0];
                    return;
                }

            }


            inline static unsigned int charToUnsignInt(char* x, int L) {
                unsigned int val;
                switch (L) {
                case 2:
                    val = ( 0x0000FF00 & (*x << 8)) | \
                          (0x000000FF & (*(x+1)) ) ;
                    break;

                case 4:
                    val = ( 0xFF000000 & (*x << 24) )    |   \
                          ( 0x00FF0000 & (*(x+1) << 16) ) |   \
                          ( 0x0000FF00 & (*(x+2) << 8) ) |   \
                          ( 0x000000FF & (*(x+3)) );
                    break;
                    /*
					case 8:
						val = 0xFF00000000000000 & (*x << 56)     |   \
						      0x00FF000000000000 & (*(x+1) << 48) |   \
						      0x0000FF0000000000 & (*(x+2) << 40) |   \
						      0x000000FF00000000 & (*(x+3) << 32) |   \
						      0x00000000FF000000 & (*(x+4) << 24) |   \
						      0x0000000000FF0000 & (*(x+5) << 16) |   \
						      0x000000000000FF00 & (*(x+6) << 8)  |   \
						      0x00000000000000FF & (*(x+7))  ;
						break;
*/
                default:
                    val = 0x000000FF & (*x);
                    break;

                }

                return val;

            }

            inline static string CharArrayHexFormat(CharArray& obj) {
                ostringstream os;
                os.setf( ios::hex, ios::basefield);
                os.setf(ios::showbase);
                char *p = obj.getBuffer();
                for ( int i=0; i< obj.getSize(); i++ ) {
                    unsigned char v = static_cast<unsigned char> (*(p+i));
                    os << (int)v;
                    if ( i!=obj.getSize()-1)
                        os << ",";
                }

                os.flags(ios::dec);
                return os.str();
            }

            inline static float charToFloat(char* x, int L) {

                float res = 0;
                int exponent;
                bool neg =  (*x & 0x80) == 0x80;
                std::bitset<24> mant;
                int pwr;

                if (L==4)   {
                    for (int i=0; i<24; i++) {
                        if (  ( ( *(x+1+i/8) << i%8) & 0x80 ) == 0x80)
                            mant.set(23-i);
                        else
                            mant.reset(23-i);
                    }
                    mant.set(23);

                    exponent = ( 0xFE & (*x << 1) ) | (( 0x80 & *(x+1) ) >> 7 );
                    exponent -= 127;
                    pwr = exponent;
                    for ( int m=23; m >-1; m-- ) {  // loop thru bitset container
                        if (mant[m])
                            res += pow(2, pwr);
                        pwr--;
                    }
                    if (neg)
                        res *= -1;
                }


                return res;

            }


            inline static double charToDouble(char* x, int L) {

                double res = 0;
                int exponent;
                bool neg =  (*x & 0x80) == 0x80;
                std::bitset<53> mant;
                int pwr;

                if (L==4)   {
                    for (int i=0; i<53; i++) {
                        if (  ( ( *(x+1+i/8) << i%8) & 0x80 ) == 0x80)
                            mant.set(52-i);
                        else
                            mant.reset(52-i);
                    }
                    mant.set(52);

                    exponent = ( 0xFE & (*x << 1) ) | (( 0x80 & *(x+1) ) >> 7 );
                    exponent -= 127;
                    pwr = exponent;
                    for ( int m=52; m >-1; m-- ) {  // loop thru bitset container
                        if (mant[m])
                            res += pow(2, pwr);
                        pwr--;
                    }
                    if (neg)
                        res *= -1;
                }


                return res;

            }



        };


    }

}




#endif /*UTIL_H_*/
